package com.ubing.boot.notesforjava.test.juc;

import com.ubing.boot.notesforjava.utils.unSafeUtils;
import sun.misc.Unsafe;

import java.sql.Time;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName : MyContainer3_cas
 * @Description : MyContainer3_cas
 * @Author : ubing
 * @Date: 2023-03-14 14:26
 */
public class MyContainer3_cas<T> {

    //   采用CAS无锁编程
    private volatile LinkedList<T> lists =  new LinkedList();
    // 记录list集合里的元素个数
    private volatile int number=0;

    //  number的偏移量
    private static long numberOffset;

    private volatile long lock=0L;
    private static long lockOffset;

    private static Unsafe unsafe;
    //  CAS 乐观锁

    //  sync 悲观

    static {
        try {
            unsafe= unSafeUtils.getInstance();
            numberOffset=unsafe.objectFieldOffset(MyContainer3_cas.class.getDeclaredField("number"));
            lockOffset=unsafe.objectFieldOffset(MyContainer3_cas.class.getDeclaredField("lock"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

/// 1000 -> syc 1 -> await
    /// 1000 -> cas 1 ->999
    public void put(T t) {
//        unsafe.fullFence(); // 读写屏障，线程可见
        int cheack=0;
        while (true) {
            if ((cheack=unsafe.getIntVolatile(this,numberOffset)) < 10 && unsafe.compareAndSwapInt(this, numberOffset, cheack, cheack + 1)) {
                while(!unsafe.compareAndSwapLong(this, lockOffset, 0L, Thread.currentThread().getId()));
                lists.add(t);
                while(!unsafe.compareAndSwapLong(this, lockOffset, Thread.currentThread().getId(),0L));
//                synchronized (this){
//                    lists.add(t);
//                }
                break;
            }
        }
    }

    public T get() {
//        unsafe.fullFence();
        T t=null;
        int cheack=0;
        reTry: while (true){
                try { // 2 -> 1  ->0  1
                    if((cheack=unsafe.getIntVolatile(this,numberOffset))>0&&unsafe.compareAndSwapInt(this,numberOffset,cheack,cheack-1)){ // 前面过了，后面
                        while(!unsafe.compareAndSwapLong(this, lockOffset, 0L, Thread.currentThread().getId()));
                        t=lists.removeFirst();
                        while(!unsafe.compareAndSwapLong(this, lockOffset, Thread.currentThread().getId(),0L));
                        return t;
//                        synchronized (this) {
//                            return lists.removeFirst();
//                        }
                    }
                }catch (NoSuchElementException e){
//                    unsafe.putInt(this,numberOffset,unsafe.getIntVolatile(this,numberOffset)+1);
                    while (true){
                        if(unsafe.compareAndSwapInt(this,numberOffset,unsafe.getIntVolatile(this,numberOffset),unsafe.getIntVolatile(this,numberOffset)+1)){
                            continue reTry;
                        }
                    }
                }finally {
//                    while(!unsafe.compareAndSwapLong(this, lockOffset, Thread.currentThread().getId(),0L));

                }
            }
    }

    public static void main(String[] args) throws InterruptedException {
        MyContainer3_cas<String> container = new MyContainer3_cas<>();
        AtomicInteger a=new AtomicInteger(0);
        CountDownLatch countDownLatch = new CountDownLatch(24);
        // 启动生产者线程  2 -> 25 50
        for (int i = 0; i <4 ; i++) {
            new Thread(()->{
                for (int j = 0; j < 25; j++) {
                    container.put(Thread.currentThread().getId()+"--"+j);
                }
                countDownLatch.countDown();
            },"p"+i).start();
        }

        // 启动消费者线程  10 -> 5   50
        for (int i = 0; i <20 ; i++) {
            new Thread(()->{
                for (int j = 0; j <5 ; j++) {
                    System.out.println(Thread.currentThread().getId()+"=="+container.get());
                    a.getAndIncrement();
                }
                countDownLatch.countDown();
            },"c"+i).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

//        Thread.sleep(2000);
        System.out.println(a.get());
    }
}
